package wxk.interview.queue.block;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author wangxuekai
 * @version 2.2
 * @Date 2017/3/21.
 * @since 2.2
 */
public class BlockQueue {

    private final Condition notFull;
    private final Condition notEmpty;
    private final ReentrantLock lock;
    private int count;
    private int putIndex, takeIndex;
    private  String[] queue ;

    public BlockQueue(int cap){
        this.queue = new String[cap];
        this.lock = new ReentrantLock(false);
        notEmpty = this.lock.newCondition();
        notFull = this.lock.newCondition();
    }

    public void put(String s)throws InterruptedException {
        ReentrantLock lock = this.lock;

        try {
            System.out.println("开始存数据:"+s);
            lock.lockInterruptibly();
            while (count == queue.length){
                notFull.await();
            }
            insert(s);
            System.out.println("存入数据,共有:"+count);
        } finally {
            lock.unlock();
        }
    }

    public String take() throws InterruptedException {
        ReentrantLock lock = this.lock;
        try {
            System.out.println("开始取数据..");
            lock.lockInterruptibly();
            while (count == 0){
                notEmpty.await();
            }
            return extract();
        }finally {
            lock.unlock();
        }
    }

    private String extract() {
        String[] item = this.queue;
        String s = item[takeIndex];

        takeIndex = inc(takeIndex);
        --count;
        notFull.signal();
        System.out.println("取出数据:"+s);
        return s;
    }

    private void insert(String e){
        queue[putIndex] = e;
        putIndex = inc(putIndex);
        ++count;
        notEmpty.signal();
    }

    final int inc(int i){
        return (++i == this.queue.length)? 0 : i;
    }

    public static void main(String[] args) {
        final BlockQueue queue = new BlockQueue(10);

        new Thread(new Runnable() {
            public void run() {
              for (int i = 0; i < 20; i++){
                  try {
                      queue.put(i+"a");
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }finally {
                      try {
                          Thread.currentThread().sleep(100);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
              }
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                while (true){
                    try {
                        System.out.println(queue.take());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }finally {
                        try {
                            Thread.currentThread().sleep(300);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();

        while (true){}

    }
}
